package com.example.novelweb.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.novelweb.common.BaseResponse;
import com.example.novelweb.common.ErrorCode;
import com.example.novelweb.common.ResultUtils;
import com.example.novelweb.constant.UserConstant;
import com.example.novelweb.exception.BusinessException;
import com.example.novelweb.exception.ThrowUtils;
import com.example.novelweb.model.dto.chapter.ChapterAddRequest;
import com.example.novelweb.model.dto.chapter.ChapterSaveRequest;
import com.example.novelweb.model.dto.chapter.ChapterSwitchRequest;
import com.example.novelweb.model.entity.Chapter;
import com.example.novelweb.model.enums.ChapterStatus;
import com.example.novelweb.model.vo.ChapterInfo;
import com.example.novelweb.model.vo.ChapterVO;
import com.example.novelweb.model.vo.NovelVO;
import com.example.novelweb.model.vo.UserVO;
import com.example.novelweb.service.ChapterService;
import com.example.novelweb.mapper.ChapterMapper;

import com.example.novelweb.service.NovelService;
import com.example.novelweb.service.PermissionService;

import com.example.novelweb.utils.FileUtils;
import com.example.novelweb.utils.UserUtils;
import com.example.novelweb.utils.WordCheck.WordCheckUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;



/**
* @author PERSON
* @description 针对表【chapter(小说章节)】的数据库操作Service实现
* @createDate 2025-02-09 01:41:52
*/
@Service
public class ChapterServiceImpl extends ServiceImpl<ChapterMapper, Chapter>
    implements ChapterService{

  private final Path chapterResPath = Paths.get(UserConstant.CHAPTER_RES_TXT_PATH).toAbsolutePath().normalize();


  @Resource
  private PermissionService permissionService;

  @Resource
  private NovelService novelService;


  // chapter.status == 2 (ChapterStatus.PUBLISHED), novelId = ? ; hide Chapter.status
  @Override
  public BaseResponse<List<ChapterVO>> listAllByNovelId(Long novelId) {
    List<ChapterVO> list = getBaseMapper().listAllByNovelId(novelId,ChapterStatus.PUBLISHED.ordinal());
    return ResultUtils.success(list);
  }

  /**
   * show Chapter.status
   * accept Roles : admin, owner
   * */
  @Override
  public BaseResponse<List<Chapter>> listMyNovel(Long novelId) {
    // 校验登录
    UserVO userVO = UserUtils.LoginCheck();
    if( userVO== null) {
      throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR,"用户未登录");
    }
    //鉴权
    Long userId = userVO.getId();
    if(!permissionService.checkAdminRight(userVO)
        && !permissionService.checkNovelOwnerRight(userId,novelId)
    ) {
      throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"没有查看该作品的权限");
    }

    List<Chapter> list = query()
        .select("id","title","res","updateTime","status")
        .eq("novelId",novelId).list();
    return ResultUtils.success(list);
  }


  /**
   * accept Roles : admin, owner  IF status
   * */
  @Override
  public BaseResponse<Chapter> getChapterById(Long chapterId) {
    Chapter one = lambdaQuery().eq(Chapter::getId,chapterId).one();
    if(!one.getStatus().equals(ChapterStatus.PUBLISHED.ordinal())) {
      // 未登录
      UserVO userVO = UserUtils.LoginCheck();
      if(userVO == null) {
        throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"无权");
      }
      // 鉴权: admin or owner
      if(!permissionService.checkAdminRight(userVO)
          && !permissionService.checkNovelOwnerRight(userVO.getId(),one.getNovelId())
      ) {
        throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"无权");
      }
    }

    return ResultUtils.success(one);
  }

  @Override
  public BaseResponse<List<ChapterInfo>> listReviewingChapter() {
    UserVO userVO = UserUtils.LoginCheck();
    if(userVO == null) {
      throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"无权");
    }
    if(!permissionService.checkAdminRight(userVO)) {
      throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"无权");
    }

    List<Chapter> chapters = lambdaQuery().eq(Chapter::getStatus,ChapterStatus.REVIEWING.ordinal())
        .select(Chapter::getId,Chapter::getNovelId,Chapter::getTitle
            ,Chapter::getRes,Chapter::getUpdateTime)
        .list();
    List<ChapterInfo> list = new ArrayList<>();
    for (Chapter chapter:chapters) {
      ChapterInfo info = new ChapterInfo();
      BeanUtils.copyProperties(chapter,info);

      NovelVO novelVO = novelService.getSimpleInfo(chapter.getNovelId());
      info.setNovelVO(novelVO);

      list.add(info);
    }

    return ResultUtils.success(list);
  }


  /**
   * accept Roles : owner
   * */
  @Override
  public BaseResponse<Long> create(ChapterAddRequest chapterAddRequest) {
    // 校验已登录
    UserVO userVO = UserUtils.LoginCheck();
    if( userVO== null) {
      throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR,"用户未登录");
    }
    Long userId = userVO.getId();
    Long novelId = chapterAddRequest.getNovelId();

    // 校验权限: owner
    ThrowUtils.throwIf( !permissionService.checkNovelOwnerRight(userId,novelId),
        ErrorCode.NO_AUTH_ERROR,"没有该作品的权限");

    // 校验格式
    String title = chapterAddRequest.getTitle();
    // 255/3 = 85
    if(title.length() > 80) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR,"标题字数过长(>80)");
    }
    String txt = chapterAddRequest.getTxt();
  //    if(txt.length() < 1000) {
  //      throw new BusinessException(ErrorCode.PARAMS_ERROR,"正文字数不足(<1000)");
  //    }

    // file_save
    String res = uploadTxt(userId,novelId,txt);

    // sql_Ops
    Chapter chapter = new Chapter();
    chapter.setNovelId(novelId);
    chapter.setTitle(title);
    chapter.setRes(res);
    boolean result = save(chapter);
    ThrowUtils.throwIf(!result,ErrorCode.OPERATION_ERROR);

    return ResultUtils.success(chapter.getId());
  }

  /**
   * accept Roles : owner
   * */
  @Override
  public BaseResponse<Boolean> save(ChapterSaveRequest chapterSaveRequest) {
    // 校验已登录
    UserVO userVO = UserUtils.LoginCheck();
    if( userVO== null) {
      throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR,"用户未登录");
    }
    // 权限鉴定
    Long userId = userVO.getId();
    Long chapterId = chapterSaveRequest.getId();

    Chapter item = lambdaQuery().select(Chapter::getNovelId,Chapter::getRes)
        .eq(Chapter::getId,chapterId).one();
    Long novelId = item.getNovelId();

    if(!permissionService.checkNovelOwnerRight(userId,novelId)) {
      throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"没有权限");
    }

    // 校验格式
    String title = chapterSaveRequest.getTitle();
    // 255/3 = 85
    if(title.length() > 80) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR,"标题字数过长(>80)");
    }
    String txt = chapterSaveRequest.getTxt();
  //    if(txt.length() < 1000) {
  //      throw new BusinessException(ErrorCode.PARAMS_ERROR,"正文字数不足(<1000)");
  //    }

    // file_rewrite
    rewriteTxt(item.getRes(), txt);

    // sql_Ops
    boolean result = lambdaUpdate().eq(Chapter::getId,chapterId)
        .set(Chapter::getTitle,title)
        .update();
    ThrowUtils.throwIf(!result,ErrorCode.OPERATION_ERROR);

    return ResultUtils.success(true);
  }

  /**
   * accept Roles : admin, owner
   * */
  @Override
  public BaseResponse<Boolean> switchStatus(ChapterSwitchRequest chapterSwitchRequest) {
    // 校验已登录
    UserVO userVO = UserUtils.LoginCheck();
    if( userVO== null) {
      throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR,"用户未登录");
    }
    // 权限鉴定
    Long userId = userVO.getId();
    Long chapterId = chapterSwitchRequest.getId();

    Chapter item = lambdaQuery().select(Chapter::getNovelId,Chapter::getRes)
        .eq(Chapter::getId,chapterId).one();
    Long novelId = item.getNovelId();

    // 权限限定操作
    int status = chapterSwitchRequest.getStatus();
    if(permissionService.checkAdminRight(userVO)) {
      // all accept
    } else if (permissionService.checkNovelOwnerRight(userId,novelId)) {
      if(status >ChapterStatus.REVIEWING.ordinal()) {
        throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"没有权限");
      }
    } else {
      throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"没有权限");
    }

    // sql_Ops
    boolean result = lambdaUpdate().eq(Chapter::getId,chapterId)
        .set(Chapter::getStatus,status)
        .update();
    ThrowUtils.throwIf(!result,ErrorCode.OPERATION_ERROR);

    return ResultUtils.success(true);
  }


  /**
   * accept Roles : admin, owner
   * */
  @Override
  public BaseResponse<Boolean> deleteChapter(Long chapterId) {
    // 校验已登录
    UserVO userVO = UserUtils.LoginCheck();
    if( userVO== null) {
      throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR,"用户未登录");
    }
    // 权限鉴定
    long userId = userVO.getId();

    Chapter item = lambdaQuery().select(Chapter::getNovelId)
        .eq(Chapter::getId,chapterId).one();
    Long novelId = item.getNovelId();
    if(!permissionService.checkAdminRight(userVO)
        && !permissionService.checkNovelOwnerRight(userId,item.getNovelId())
    ) {
      throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"没有权限");
    }

    int result = getBaseMapper().deleteById(chapterId);
    ThrowUtils.throwIf(result<=0,ErrorCode.OPERATION_ERROR,"删除章节失败");
    return ResultUtils.success(true);
  }


//------ private functions :-------


  private String uploadTxt(Long userId,Long novelId,String txt) {
    try {
      // 为对应小说创建文件夹
      Path dir = chapterResPath.resolve(novelId.toString());
      if(!Files.exists(dir)) {
        Files.createDirectories(dir);
      }

      // unique fileName generator
      String fileName = FileUtils.uniqueFileNameGenerate(userId);
      Path target = dir.resolve(fileName + ".txt");

      //TODO : 异步进行 并进行脱敏处理
      asyncWriteTxtFile(target,txt);

      // 返回相对路径
      return UserConstant.SERVER_URL_PREFIX+ UserConstant.CHAPTER_RES_TXT_PATH + chapterResPath.relativize(target);

    } catch (IOException e) {
      throw new BusinessException(ErrorCode.SYSTEM_ERROR,"上传保存失败");
    }
  }
  private Boolean rewriteTxt(String outsidePath,String txt) {
    try {
      // 去掉"/api/"
      String path = outsidePath.substring(UserConstant.SERVER_URL_PREFIX.length());
      Path target = Paths.get(path).toAbsolutePath().normalize();

//      if(!Files.exists(target)) {
//        throw new BusinessException(ErrorCode.OPERATION_ERROR,"目标文件不存在");
//      }

      //TODO : 异步进行 并进行脱敏处理
      asyncWriteTxtFile(target,txt);

      return true;

    } catch (Exception e) {
      throw new BusinessException(ErrorCode.SYSTEM_ERROR,"上传保存失败");
    }

  }


  /* Files.write(path,bytes[],options=null)的默认行为：创建一个新文件或重写现有文件 */
  @Async
  protected void asyncWriteTxtFile(Path path, String txt) {
    try {
      // 敏感词处理
      String processResult = WordCheckUtil.findWordsAndReplace(txt);

      if (processResult == null) {
        Files.write(path,txt.getBytes(StandardCharsets.UTF_8));
      } else {
        Files.write(path,processResult.getBytes(StandardCharsets.UTF_8));
      }


    } catch (IOException e) {
      throw new BusinessException(ErrorCode.SYSTEM_ERROR,"上传保存失败");
    }

  }

}




